﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using EnvSafe.Expression;
using System.ComponentModel;
using Heroius.Extension;

namespace Heroius.Abacus
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();
            core.RegistCommonSymbolAndVariableMapping();
            Operators = core.OpFactory.GetAvailableOperatorNames().Select(n => new OpEntity() { OpName = n, Description = OpInfo.ResourceManager.GetString(n) });

            DataContext = this;
            WriteRecord("叨算盘 4.0 by Heroius", RecordType.Info);

            TbExp.Focus();
        }

        public event PropertyChangedEventHandler PropertyChanged;
        void RaisePropertyChangedEvent(string PropertyName)
        {
            var temp = PropertyChanged;
            if (temp != null)
            {
                temp(this, new PropertyChangedEventArgs(PropertyName));
            }
        }

        #region Expression Part

        Interpreter core = new Interpreter();

        public string Expression { get { return _expression; } set { _expression = value; RaisePropertyChangedEvent("Expression"); } }
        string _expression;

        public void Calculate()
        {
            try
            {
                WriteRecord("输入: " + Expression, RecordType.Input);
                var r = core.GenerateProcedure(Expression).Calculate();
                WriteRecord("输出: " + r.ToString(), RecordType.Output);
            }
            catch (Exception ex)
            {
                WriteRecord("错误: " + ex.Message, RecordType.Error);
            }
        }

        public IEnumerable<OpEntity> Operators { get; set; }
        public ObservableCollection<RecordEntity> Records { get; set; } = new ObservableCollection<RecordEntity>();

        void WriteRecord(string text, RecordType rtype)
        {
            Records.Add(new RecordEntity() { Text = text, Color = rtype.RenderColor() });
        }

        private void OpItemDbClick(object sender, MouseButtonEventArgs e)
        {
            if (e.ClickCount > 1)
            {
                var op = ((sender as TextBlock).DataContext as OpEntity);
                InsertOp(op);
            }
            e.Handled = true;
            TbExp.Focus();
        }

        void InsertOp(OpEntity op)
        {
            var s = TbExp.SelectionStart;
            TbExp.SelectedText = op.OpName + "()";
            TbExp.SelectionStart = s + op.OpName.Length + 1;
            TbExp.SelectionLength = 0;
        }

        private void ExpPartKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                Calculate();
            }
        }

        #endregion

        #region Iter Part

        //todo:文件导入导出

        Iterator itor;

        public ObservableDictionary<string, string> Variables { get; set; } = new ObservableDictionary<string, string>();
        public ObservableCollection<Tuple<string, string, Procedure>> Equations { get; set; } = new ObservableCollection<Tuple<string, string, Procedure>>();
        public ObservableCollection<VarEntity> ItorVars { get; set; } = new ObservableCollection<VarEntity>();

        public int ItorStepTotal { get { return _itorStepTotal; } set { _itorStepTotal = value; RaisePropertyChangedEvent("ItorStepTotal"); } }
        int _itorStepTotal = 0;
        public int ItorStepNext { get; set; } = 1;

        public void SetItorate()
        {
            itor = new Iterator(core, Variables.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), Equations.Select(ssp => new Tuple<string, Procedure>(ssp.Item2, ssp.Item3)).ToList());
            //recreate itor vars
            ItorVars.Clear();
            ItorStepTotal = 0;
            foreach (var item in itor.VarPool.Keys)
            {
                ItorVars.Add(new VarEntity() { Key = item, Value = itor.VarPool[item] });
            }
        }

        public void Itorate()
        {
            if (itor == null)
            {
                SetItorate();
            }
            for (int i = 0; i < ItorStepNext; i++)
            {
                itor.Next();
                ItorStepTotal++;
            }
            foreach (var item in ItorVars)
            {
                item.Value = itor.VarPool[item.Key];
            }
        }

        private void DelItorEqua(object sender, RoutedEventArgs e)
        {
            var eq = (Tuple<string, string, Procedure>)((sender as Button).DataContext);
            Equations.Remove(eq);
        }

        private void DelItorVar(object sender, RoutedEventArgs e)
        {
            var v = (KeyValuePair<string, string>)((sender as Button).DataContext);
            Variables.Remove(v.Key);
        }

        public void AddItorEqua()
        {
            var dia = new DiaNewItorEq();
            dia.Closed += (ss, ee) =>
              {
                  if (dia.DialogResult == true)
                  {
                      try
                      {
                          Equations.Add(new Tuple<string, string, Procedure>(string.Format("{0}={1}", dia.Target, dia.Express), dia.Target, core.GenerateProcedure(dia.Express)));
                      }
                      catch(Exception ex)
                      {
                          MessageBox.Show(string.Format("生成过程出错:{0}", ex.Message));
                      }
                  }
              };
            dia.ShowDialog();
        }

        public void AddItorVar()
        {
            var dia = new DiaNewItorVar();
            dia.Closed += (ss, ee) =>
            {
                if (dia.DialogResult == true)
                {
                    Variables.Add(dia.Key, dia.Value);
                }
            };
            dia.ShowDialog();
        }

        #endregion

    }

    public enum RecordType
    {
        Info,
        Input,
        Output,
        Error
    }

    public static class RecordTypeExtension
    {
        public static Color RenderColor(this RecordType rtype)
        {
            switch (rtype)
            {
                default:
                case RecordType.Info: return Colors.Purple;
                case RecordType.Input: return Colors.Orange;
                case RecordType.Output: return Colors.Green;
                case RecordType.Error: return Colors.Red;
            }
        }
    }
}
